package com.cpit.qualitycontrol.service.impl;

import com.cpit.platform.log.LogOperator;
import com.cpit.qualitycontrol.common.constant.ActivitiConstant;
import com.cpit.qualitycontrol.service.ActivitiService;
import com.github.pagehelper.StringUtil;
import org.activiti.engine.HistoryService;
import org.activiti.engine.ManagementService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.activiti.engine.task.TaskQuery;
import org.apache.poi.ss.formula.functions.T;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * Created by xxx on 2017/10/1.
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class ActivitiServiceImpl implements ActivitiService {

    private final String loggerName = this.getClass().getName();

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private TaskService taskService;

    @Autowired
    private HistoryService historyService;

    @Autowired
    private ManagementService managementService;

    @Override
    public String createWorkOrder(Integer createUserId, String businessKey) {

        //启动流程实例，并分派创建任务
        Map<String, Object> createVariables = new HashMap<String, Object>();
        createVariables.put("createUser", createUserId);
        ProcessInstance pi = runtimeService
                .startProcessInstanceByKey(ActivitiConstant.PROCESS_DEFINITION_KEY, businessKey, createVariables);
        LogOperator.info(loggerName, "activiti processInstance id:" + pi.getId());

        //完成创建任务，创建派发工单任务
        Map<String, Object> assingVariables = new HashMap<String, Object>();
        assingVariables.put("assingUsers", "potevioEngineeringDept");

        Task createTask = taskService.createTaskQuery().processInstanceId(pi.getId())
                .taskAssignee(String.valueOf(createUserId)).singleResult();
        taskService.complete(createTask.getId(), assingVariables);
        return pi.getId();
    }

    @Override
    public List<String> queryNotAssingTask() {

        List<Task> assignTaskList = taskService.createTaskQuery()
                .taskDefinitionKey(ActivitiConstant.ASSIGN_TASK_DEFINITIONKEY)
                .list();

        List<String> processInstanceIdList = assignTaskList.stream()
                .map(task -> task.getProcessInstanceId())
                .collect(Collectors.toList());

        return processInstanceIdList;
    }

    @Override
    public List<String> queryHistoryTaskExecutionIdsByUserId(Integer userId, String organizationTeamCode) {
        // %c 对应ActivitiConstant.CONSTRUCT_TASK_DEFINITIONKEY  ActivitiConstant.CHECK_TASK_DEFINITIONKEY
        List<HistoricTaskInstance> historicTaskInstanceList = historyService.createHistoricTaskInstanceQuery()
                .taskAssignee(String.valueOf(userId))
                .taskDefinitionKeyLike("c%").list();

        Set<String> executionIds = historicTaskInstanceList.stream()
                .filter(task -> task.getEndTime() != null)
                .map(task -> task.getExecutionId()).collect(Collectors.toSet());

        return new ArrayList<String>(executionIds);
    }


    @Override
    public List<String> queryTaskExecutionIDByUserId(Integer userId,
                                                     String organizationTeamCode, boolean isEnginnerDept) {

        String baseQueryStr = "SELECT * FROM " +
                managementService.getTableName(Task.class) + " T ";

        List<Task> checkTaskList = null;
        if (isEnginnerDept == true) {
            checkTaskList = taskService.createNativeTaskQuery().sql(baseQueryStr +
                    " WHERE T.TASK_DEF_KEY_ = '" + ActivitiConstant.CHECK_TASK_DEFINITIONKEY + "'").list();
        }

        List<Task> constructTaskList =
                taskService.createNativeTaskQuery().sql(baseQueryStr +
                        " WHERE T.TASK_DEF_KEY_ = '" + ActivitiConstant.CONSTRUCT_TASK_DEFINITIONKEY + "' AND '" +
                        organizationTeamCode + "' LIKE CONCAT(ASSIGNEE_,'%')").list();

        Set<Task> todoList = new HashSet<>();
        if (constructTaskList != null && constructTaskList.size() > 0)
            todoList.addAll(constructTaskList);
        if (checkTaskList != null && checkTaskList.size() > 0)
            todoList.addAll(checkTaskList);

        List<String> executionIDList = todoList.stream()
                .map(task -> task.getExecutionId())
                .collect(Collectors.toList());

        return executionIDList;
    }


    @Override
    public Map<String, String> assignWorkOrder(String processInstanceBusinessKey,
                                               Integer assignUserId,
                                               Map<String, String> organizationTeamMap) throws Exception {

        Map<String, String> rtnMap = new HashMap<>();

        //查询待派发任务
        Task assignTask = getEngineerDeptAssignTask(ActivitiConstant.ASSIGN_TASK_DEFINITIONKEY,
                processInstanceBusinessKey);

        //接收任务
        claimTask(assignUserId, assignTask.getId());

        Map<String, Object> assignVariables = new HashMap<String, Object>();

        List<String> teamIdList = new ArrayList<>();

        for (String subTaskId : organizationTeamMap.keySet()) {
            teamIdList.add(organizationTeamMap.get(subTaskId));
        }

        assignVariables.put("organizationTeamList", teamIdList);
        taskService.complete(assignTask.getId(), assignVariables);

        List<Task> taskList = taskService.createTaskQuery()
                .processInstanceBusinessKey(processInstanceBusinessKey).list();

        for (int i = 0; i < taskList.size(); i++) {
            Task task = taskList.get(i);
            String assign = task.getAssignee();
            Iterator<Map.Entry<String, String>> iterator = organizationTeamMap.entrySet().iterator();
            while (iterator.hasNext()) {
                Map.Entry<String, String> entry = iterator.next();
                if (entry.getValue().contains(assign)) {
                    rtnMap.put(entry.getKey(), task.getExecutionId() + ":" + task.getId());
                    iterator.remove();
                    break;
                }
            }

        }

        return rtnMap;
    }

    @Override
    public String queryTaskId(String actProcInstId, String actExecutionId, Integer userId, String taskDefinitionKey) {

        TaskQuery taskQuery = taskService.createTaskQuery();

        if (StringUtil.isNotEmpty(actProcInstId)) {
            taskQuery = taskQuery.processInstanceId(actProcInstId);
        }

        if (StringUtil.isNotEmpty(actExecutionId)) {
            taskQuery = taskQuery.executionId(actExecutionId);
        }

//        if (userId != null && !userId.equals(0)) {
//            taskQuery = taskQuery.taskInvolvedUser(String.valueOf(userId));
//        }

        if (StringUtil.isNotEmpty(taskDefinitionKey)) {
            taskQuery = taskQuery.taskDefinitionKey(taskDefinitionKey);
        }

        Task task = taskQuery.singleResult();

        if (task != null) {
            return task.getId();
        } else {
            return null;
        }
    }

    @Override
    public void completeConstructTask(String actTaskId, Boolean isCheck) {

        Map<String, Object> checkVariables = new HashMap<String, Object>();
        checkVariables.put("isCheckTask", isCheck);

        //完成创建任务，创建派发工单任务
        if (isCheck == true) {
            checkVariables.put("checkUser", "potevioEngineeringDept");
            taskService.complete(actTaskId, checkVariables);
        } else {
//            checkVariables.put("checkUser", "potevioEngineeringDept");
            taskService.complete(actTaskId, checkVariables);
        }
    }

    @Override
    public void completeCheckTask(String actTaskId, Boolean isAccred, String organizationTeamCode) {
        Map<String, Object> checkVariables = new HashMap<String, Object>();
        checkVariables.put("isAccred", isAccred);
        if (isAccred == true) {
            taskService.complete(actTaskId, checkVariables);
        } else {
            checkVariables.put("organizationTeam",
                    organizationTeamCode);
            taskService.complete(actTaskId, checkVariables);
        }
    }

    @Override
    public synchronized void claimTask(Integer userId, String actTaskId) {
        // 清除任务 assignee
        taskService.claim(actTaskId, null);
        // 重新设置 assignee
        taskService.claim(actTaskId, String.valueOf(userId));
    }


    private Task getEngineerDeptAssignTask(String taskDefinitionKey,
                                           String processInstanceBusinessKey) throws Exception {
        Task claimTask = taskService.createTaskQuery()
                .taskDefinitionKey(taskDefinitionKey)
                .processInstanceBusinessKey(processInstanceBusinessKey).singleResult();

        if (claimTask == null) {
            LogOperator.debug(loggerName, "任务不存在，工单ID:" + processInstanceBusinessKey);
            throw new Exception("任务不存在!");
        }
        return claimTask;
    }

    @Override
    public Boolean isProcessInstanceEndById(String processInstanceId) {
        ProcessInstance processInstance = runtimeService
                .createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();

        return processInstance == null;
    }
}
